﻿using System;
using System.Collections.Concurrent;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace Actor.Net.Network.Gate
{
    /// <summary>
    /// 通讯管道基类
    /// </summary>
    public abstract class GateBaseChannel : IDisposable
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="netService">网络服务对象</param>
        /// <param name="channelId">通讯管道Id</param>
        public GateBaseChannel(GateBaseService netService, int channelId)
        {
            this.NetService = netService;
            this.ChannelId = channelId;
            this.ChannelContext = new GateChannelContext(this);
            this.Parser = new GatePacketParser();
            this.StartTime = GateTimeUtils.NowMilliSecond();
            this.LastReceiveMillisecond = GateTimeUtils.NowMilliSecond();
        }

        /// <summary>
        /// 拥有此管道连接业务拥有者Id，比如PlayerId代表该连接属于某个玩家的长链接。
        /// </summary>
        public long OwnerId { get; set; }
        /// <summary>
        /// 开始连接时间
        /// </summary>
        public long StartTime;
        /// <summary>
        /// 连接了多少毫秒
        /// </summary>
        public long ConnectedMilliseconds => GateTimeUtils.NowMilliSecond() - this.StartTime;
        /// <summary>
        /// 最后一次接收消息时间毫秒
        /// </summary>
        public long LastReceiveMillisecond;
        /// <summary>
        /// 没有接收到消息时长毫秒
        /// </summary>
        public long NoReceiveMessageMilliseconds => GateTimeUtils.NowMilliSecond() - this.LastReceiveMillisecond;
        /// <summary>
        /// 是否已经掉线
        /// </summary>
        public bool IsDropped => this.NoReceiveMessageMilliseconds > this.Network.ConnectionDroppedMilliseconds;
        /// <summary>
        /// Network Id
        /// </summary>
        public int NetworkId => this.Network.Id;
        /// <summary>
        /// 管道Id
        /// </summary>
        public int ChannelId { get; internal set; }
        /// <summary>
        /// 网络服务对象实例
        /// </summary>
        public GateBaseService NetService { get; }
        /// <summary>
        /// 网络类对象实例
        /// </summary>
        public GateNetwork Network => this.NetService.Network;
        /// <summary>
        /// 本地IP端口
        /// </summary>
        public EndPoint LocalEndPoint { get; set; }
        /// <summary>
        /// 远程IP端口
        /// </summary>
        public EndPoint RemoteEndPoint { get; set; }
        /// <summary>
        /// 网络服务类型(客户端或者服务端)
        /// </summary>
        public NetServiceType ServiceType => this.NetService.ServiceType;
        /// <summary>
        /// 网络类型TCP、KCP、WebSocket
        /// </summary>
        public GateNetType NetType => this.Network.NetType;
        /// <summary>
        /// Socket对象
        /// </summary>
        public Socket NetSocket { get; protected set; }
        /// <summary>
        /// RPC调用上下文列表字典
        /// </summary>
        public ConcurrentDictionary<int, IGateCallContext> CallContextList { get; } = new ConcurrentDictionary<int, IGateCallContext>();
        /// <summary>
        /// 管道上下文
        /// </summary>
        public GateChannelContext ChannelContext { get; }
        /// <summary>
        /// 消息解析器
        /// </summary>
        protected GatePacketParser Parser { get; }
        /// <summary>
        /// 连接状态
        /// </summary>
        public abstract bool Connected { get; }
        /// <summary>
        /// 同步连接Socket，会阻塞线程
        /// </summary>
        /// <param name="timeoutMillisecond"></param>
        /// <returns></returns>
        public abstract bool Connect(int timeoutMillisecond);
        /// <summary>
        /// 异步连接Socket，非线程阻塞
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public abstract Task<bool> ConnectAsync(CancellationToken cancellationToken);
        /// <summary>
        /// 写发送网络数据包
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="count"></param>
        public abstract void Write(byte[] bytes, int count);
        /// <summary>
        /// 开始发送
        /// </summary>
        public abstract void StartSend();
        /// <summary>
        /// 读接收网络数据包
        /// </summary>
        public abstract void Read();
        /// <summary>
        /// 断开连接
        /// </summary>
        public abstract void Disconnect();
        /// <summary>
        /// 重连状态
        /// </summary>
        private volatile bool reconnecting;
        /// <summary>
        /// 重新连接
        /// </summary>
        public async void Reconnect(int retryCount = 0)
        {
            if (reconnecting)
                return;

            reconnecting = true;

            int count = 0;
            try
            {
                while (true)
                {
                    if(retryCount > 0 && count >= retryCount)
                    {
                        Action action = () => { this.NetService.OnReconnectFailed(this.ChannelContext); };
                        this.Network.Post(this.Network.ProcessContextAction, action);
                        return;
                    }

                    count++;
                    await Task.Delay(1000);

                    if (this.Connected)
                        break;

                    var cts = new CancellationTokenSource(8000);
                    if (await this.ConnectAsync(cts.Token))
                        break;
                }
            }
            finally
            {
                reconnecting = false;
            }
        }

        public abstract void Dispose();
    }
}